from game_agent import GameAgent
from anytime_alpha_beta_extended import AnyTimeAlphaBetaSearch_Extended, INFINITY
from anytime_alpha_beta import AnyTimeAlphaBetaSearch
from loa_game import DIRECTIONS 
from math import exp

class AgentPowers(GameAgent):
    '''
    AnyTimeAlphaBeta
    utility: scc
    '''

    def move(self, game_state):
        return self.alphaBeta.search(game_state)
    
    def setup(self, player, game_state, turn_time_limit, setup_time_limit):
        self.player = player
        self.prevUtil = -INFINITY
        u = lambda state: self.utility(state)
        self.alphaBeta = AnyTimeAlphaBetaSearch(self.player, 2, u, turn_time_limit)

    def utility(self, state):
        list = []
        scc = 0
        for i in xrange(0, state.size):
            for j in xrange(0,state.size):
                if not((i,j) in list):
                    if state.board[i][j] == self.player:
                        list += self._getConnectiveComponent(state, i, j, self.player)
                        scc += 1
        if 1 == scc: return INFINITY
        if not hasattr(state, "evaluator"): return exp(-scc)  
        return exp(-scc)*state.evaluator
        
    def _getConnectiveComponent(self, state, initial_row, initial_col, player):
        '''
        Performs BFS to traverse the connective component, beginning at the given coordinate.
        
        @param initial_row: The initial row coordinate.
        @param initial_col: The initial column coordinate.
        @param player: The player who's connective component we would like to traverse.
        @return: The closed set - the connective component.
        '''
        open = set()
        open.add((initial_row, initial_col))
        closed = set()
        
        while len(open) > 0:
            (row, col) = open.pop()
            closed.add((row, col))
            for direction in DIRECTIONS:
                (neighbor_row, neighbor_col) = direction.move((row, col))
                if (0 <= neighbor_row < state.size) and (0 <= neighbor_col < state.size) \
                    and (state.board[neighbor_row][neighbor_col] == player) \
                    and ((neighbor_row, neighbor_col) not in closed):
                    open.add((neighbor_row, neighbor_col))
        return closed